package cn.tj.wenda.cloud.aop;

import cn.tj.wenda.cloud.entity.LoginUserInfo;
import cn.tj.wenda.cloud.exception.BusinessException;
import cn.tj.wenda.cloud.util.DateTime;
import cn.tj.wenda.cloud.util.LoginUser;
import cn.tj.wenda.cloud.util.PrimaryKey;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.persistence.Id;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

@Component
@Aspect
public class CloudModifyDatabaseAop {

    private static Logger logger = LoggerFactory.getLogger(CloudModifyDatabaseAop.class);

    @Autowired
    PrimaryKey primaryKey;

    /**
     * 拦截数据更新方法
     * @param point
     * @return
     */
    @Around("execution(public * cn.tj.wenda.cloud.mapper.CloudUpdateMapper.*(..))")
    public Object executeUpdateDatabase(ProceedingJoinPoint point)
            throws Throwable {
        Object retVal = null;

        Object[] args = point.getArgs();
        Object beanEntity = args[0];
        if(args.length == 1) {//单一参数下启动乐观锁校验
            this.CheckVersion(point,beanEntity);
        }
        LoginUserInfo loginUserInfo = LoginUser.getLoginUserInfo();
        BeanUtils.setProperty(beanEntity, "upduserid", loginUserInfo.getUserId());
        BeanUtils.setProperty(beanEntity, "upduser", loginUserInfo.getUserName());
        BeanUtils.setProperty(beanEntity, "updtime", DateTime.getCurrDateTime());
        retVal = point.proceed(args);
        return retVal;
    }

    /**
     * 拦截数据新增方法
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("execution(public * cn.tj.wenda.cloud.mapper.CloudInsertMapper.*(..))")
    public Object executeInsertDatabase(ProceedingJoinPoint point) {
        Object retVal = null;
        try {
            Object[] args = point.getArgs();
            Object beanEntity = args[0];
            LoginUserInfo loginUserInfo = LoginUser.getLoginUserInfo();
            String currTime = DateTime.getCurrDateTime();

            //关键字为空的情况下，自动给关键字赋值
            Field[] fields = beanEntity.getClass().getDeclaredFields();
            for(Field field : fields){
                boolean isExists = field.isAnnotationPresent(Id.class);
                if(!isExists){
                    continue;
                }
                String fieldName = field.getName();
                String oriValue = BeanUtils.getProperty(beanEntity, fieldName);
                if(StringUtils.isEmpty(oriValue)) {
                    BeanUtils.setProperty(beanEntity, fieldName, primaryKey.getPrimaryKey());
                }
            }

            BeanUtils.setProperty(beanEntity,"adduserid",loginUserInfo.getUserId());
            BeanUtils.setProperty(beanEntity,"adduser",loginUserInfo.getUserName());
            BeanUtils.setProperty(beanEntity,"addtime",currTime);
            BeanUtils.setProperty(beanEntity,"tenantid",loginUserInfo.getTenantId());
            BeanUtils.setProperty(beanEntity,"upduserid",loginUserInfo.getUserId());
            BeanUtils.setProperty(beanEntity,"upduser",loginUserInfo.getUserName());
            BeanUtils.setProperty(beanEntity,"updtime", currTime);
            retVal = point.proceed(args);
        }
        catch (Throwable t){
            logger.error("拦截添加数据库数据时出错",t);
        }
        return retVal;
    }

    /**
     * 拦截数据删除方法，用于主键删除时乐观锁校验
     * @param point
     * @return
     */
    @Around("execution(public * cn.tj.wenda.cloud.mapper.CloudDeleteMapper.*(..))")
    public Object executeDeleteDatabase(ProceedingJoinPoint point)
            throws Throwable {
        Object retVal = null;

        Object[] args = point.getArgs();
        Object beanEntity = args[0];
        String methodName = point.getSignature().getName();

        if(StringUtils.equalsIgnoreCase(methodName,"deleteByPrimaryKey")) {//单一参数下启动乐观锁校验
            this.CheckVersion(point,beanEntity);
        }
        LoginUserInfo loginUserInfo = LoginUser.getLoginUserInfo();
        BeanUtils.setProperty(beanEntity, "upduserid", loginUserInfo.getUserId());
        BeanUtils.setProperty(beanEntity, "upduser", loginUserInfo.getUserName());
        BeanUtils.setProperty(beanEntity, "updtime", DateTime.getCurrDateTime());
        retVal = point.proceed(args);
        return retVal;
    }

    private void CheckVersion(ProceedingJoinPoint point,Object beanEntity) throws BusinessException,InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        Object impl = point.getTarget();
        Method m = impl.getClass().getMethod("selectByPrimaryKey", Object.class);//得到方法
        Object retBean = m.invoke(impl, beanEntity);

        if (retBean == null) {// 数据已经不存在
            throw new BusinessException("000016");
        }

        String oriVersion = BeanUtils.getProperty(retBean, "updtime");
        String newVersion = BeanUtils.getProperty(beanEntity, "updtime");
        if (StringUtils.equalsIgnoreCase(oriVersion, newVersion) == false) {
            throw new BusinessException("000023");
        }
    }
}
